
function [manager, offset] = cm_allocate(manager, size_needed, buf_id)
    offset = -1;
    best_fit_idx = -1;
    min_suitable_size = inf;

    for i = 1:length(manager.free_blocks)
        if manager.free_blocks(i).size >= size_needed && manager.free_blocks(i).size < min_suitable_size
            min_suitable_size = manager.free_blocks(i).size;
            best_fit_idx = i;
        end
    end

    if best_fit_idx == -1, return; end

    best_block = manager.free_blocks(best_fit_idx);
    offset = best_block.start;

    new_alloc_block = struct('start', offset, 'size', size_needed, 'buf_id', buf_id);
    manager.allocated_blocks = [manager.allocated_blocks; new_alloc_block];
    
    % 更新 free_blocks
    if best_block.size > size_needed
        manager.free_blocks(best_fit_idx).start = best_block.start + size_needed;
        manager.free_blocks(best_fit_idx).size = best_block.size - size_needed;
    else
        manager.free_blocks(best_fit_idx) = [];
    end
    
    % 保持 allocated_blocks 有序
    if ~isempty(manager.allocated_blocks)
        [~, sort_idx] = sort([manager.allocated_blocks.start]);
        manager.allocated_blocks = manager.allocated_blocks(sort_idx);
    end
end